home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / HENSA / MISC / SHELL.ARC / Shell / Sources / c / Save102 < prev    next >
Text File  |  1994-11-04  |  17KB  |  504 lines

  1. /*
  2.     ####             #    #     # #
  3.     #   #            #    #       #          The FreeWare C library for
  4.     #   #  ##   ###  #  # #     # ###             RISC OS machines
  5.     #   # #  # #     # #  #     # #  #   ___________________________________
  6.     #   # ####  ###  ##   #     # #  #
  7.     #   # #        # # #  #     # #  #    Please refer to the accompanying
  8.     ####   ### ####  #  # ##### # ###    documentation for conditions of use
  9.     ________________________________________________________________________
  10.  
  11.     File:    Save.Save.c
  12.     Author:  Copyright © 1994 Julian Smith and Jason Howat
  13.     Version: 1.02 (18 Jun 1994)
  14.     Purpose: Automated handling of save-as window
  15.     Mods:    13-Jun-1994 - JPS - Added support for filetypes
  16.              18-Jun-1994 - JDH - Changed sense of value returned by
  17.                   save_filesaver to be in line with rest of DeskLib.
  18.                   save_filsaver uses filename instead of stream.  Tidied code
  19.                   to use core routines and proper DeskLib conventions.  Added
  20.                   Save__KeyHandler to check for RETURN key in text icon.  For
  21.                   a RETURN key or OK click, added check that filename isn't
  22.                   just a leafname.  Changed Save__DragIconClickHandler to use
  23.                   Icon_StartSolidDrag.  Changed several routines to make
  24.                   messages in their own blocks -- they used to corrupt
  25.                   event_lastevent.  In Save__MessageHandler the initial
  26.                   reference check excludes unacknowledged messages that were
  27.                   returned.
  28.  
  29.     04 Nov 1994 Modified to work as a Shell sublibrary - JPS.
  30.                 This is because DeskLib hasn't been released with Save 1.02 yet, but
  31.                 Shell requires Save 1.02.
  32. */
  33.  
  34. #include "DeskLib:Event.h"
  35. #include "DeskLib:WimpSWIs.h"
  36. #include "DeskLib:Icon.h"
  37. #include "DeskLib:Keycodes.h"
  38. #include "DeskLib:Error.h"
  39. #include "DeskLib:Str.h"
  40. #include "Desklib:File.h"
  41.  
  42. #include "Shell.Save102.h"
  43.  
  44. #include <stdio.h>
  45. #include <string.h>
  46. #include <stdlib.h>
  47.  
  48.  
  49. void Shell_Save102_SetFiletype(Shell_Save102_saveblock *saveblock, int filetype)
  50. {
  51.   saveblock->filetype = filetype;
  52.   Icon_FileIcon(saveblock->window, saveblock->dragsprite, filetype);
  53. }
  54.  
  55.  
  56.  
  57. static void Shell_Save102__CleanIconText(window_handle window, icon_handle icon)
  58. /* used to clean up writable-icon text - these seem to be
  59.  * terminated by '\n', which is no use to <string.h> functions.
  60.  */
  61. {
  62.   icon_block iconblock;
  63.  
  64.   Wimp_GetIconState(window, icon, &iconblock);
  65.   Str_MakeASCIIZ(iconblock.data.indirecttext.buffer,
  66.                  iconblock.data.indirecttext.bufflen-1);
  67. }
  68.  
  69.  
  70. static void Shell_Save102__ResetSaveBlock(Shell_Save102_saveblock *saveblock)
  71. {
  72.   saveblock->ram_progress               = 0;
  73.   saveblock->last_message_ref           = -1;
  74.   saveblock->flags.data.we_are_dragging = FALSE;
  75. }
  76.  
  77.  
  78. static BOOL Shell_Save102__SaveDataToFilename(char *filename, Shell_Save102_saveblock *saveblock)
  79. {
  80.   BOOL Shell_Save102_ok;
  81.  
  82.   Shell_Save102_ok = saveblock->filesaver(filename, saveblock->ref);
  83.  
  84.   if(Shell_Save102_ok)
  85.     File_SetType(filename, saveblock->filetype);
  86.   else
  87.     saveblock->resulthandler(Shell_Save102_FILESAVERFAILED, saveblock);
  88.  
  89.   return Shell_Save102_ok;
  90. }
  91.  
  92.  
  93. static void Shell_Save102__CloseMenuOrSaveWindow(Shell_Save102_saveblock *saveblock)
  94.   /* A save has been completed with 'Select'.
  95.    * If we were part of a menu, close menu.
  96.    * If we were a save window, close this window.
  97.    * If none of the above, our window contains other things, (it might be the
  98.    *   main document window with a 'Quick save' icon), so do nothing.
  99.    * The Event_ handlers will be released by Save_CloseHandler and
  100.    * Save_MenusDeletedHandler, so we don't release them here.
  101.    */
  102. {
  103.   if(saveblock->flags.data.is_menu)
  104.     Wimp_CreateMenu((menu_block *)-1, 0, 0);  /* close menu */
  105.  
  106.   if(saveblock->flags.data.is_save_window)
  107.     Wimp_CloseWindow(saveblock->window);      /* close window */
  108. }
  109.  
  110.  
  111. static BOOL Shell_Save102__OKIconHandler(event_pollblock *event, void *ref)
  112. {
  113.   icon_block     iconblock;
  114.   Shell_Save102_saveblock *saveblock = (Shell_Save102_saveblock *)ref;
  115.   char           *filename;
  116.  
  117.   Wimp_GetIconState(saveblock->window, saveblock->filenameicon, &iconblock);
  118.   filename = iconblock.data.indirecttext.buffer;
  119.  
  120.   if(LeafName(filename) != filename)    /* not just a leafname in icon */
  121.   {
  122.     Shell_Save102__SaveDataToFilename(iconblock.data.indirecttext.buffer, saveblock);
  123.     Shell_Save102__ResetSaveBlock(saveblock);
  124.  
  125.     if((event->type == event_CLICK && event->data.mouse.button.data.select) ||
  126.         event->type == event_KEY)
  127.       Shell_Save102__CloseMenuOrSaveWindow(saveblock);
  128.   }
  129.   else
  130.     Error_Report(0, "To save, drag the icon to a directory display");
  131.  
  132.   return TRUE;
  133. }
  134.  
  135.  
  136. static BOOL Shell_Save102__KeyHandler(event_pollblock *event, void *ref)
  137. {
  138.   if(event->data.key.code == keycode_RETURN)
  139.     return Shell_Save102__OKIconHandler(event, ref);
  140.  
  141.   return FALSE;
  142. }
  143.  
  144.  
  145. static BOOL Shell_Save102__CancelIconHandler(event_pollblock *event, void *ref)
  146. {
  147.   UNUSED_ARG(event);
  148.  
  149.   Shell_Save102__CloseMenuOrSaveWindow((Shell_Save102_saveblock *)ref);
  150.   return TRUE;
  151. }
  152.  
  153.  
  154. static BOOL Shell_Save102__DragIconClickHandler(event_pollblock *event, void *ref)
  155. {
  156.   Shell_Save102_saveblock *saveblock = (Shell_Save102_saveblock *)ref;
  157.  
  158.   if(!event->data.mouse.button.data.dragselect &&
  159.      !event->data.mouse.button.data.dragadjust)
  160.     return FALSE;
  161.  
  162.   saveblock->flags.data.quit_after_save =
  163.                                       event->data.mouse.button.data.dragselect;
  164.  
  165.   saveblock->flags.data.we_are_dragging = TRUE;
  166.  
  167.   Icon_StartSolidDrag(saveblock->window, saveblock->dragsprite);
  168.  
  169.   return TRUE;
  170. }
  171.  
  172.  
  173. static BOOL Shell_Save102__UserDragHandler(event_pollblock *event, void *ref)
  174. {
  175.   Shell_Save102_saveblock *saveblock = (Shell_Save102_saveblock *)ref;
  176.   mouse_block    ptr;
  177.   message_block  msg;
  178.  
  179.   UNUSED_ARG(event);
  180.  
  181.   /* Is the drag nothing to do with the save drag-icon? */
  182.   if(!saveblock->flags.data.we_are_dragging)
  183.     return FALSE;
  184.  
  185.   saveblock->flags.data.we_are_dragging = FALSE;
  186.  
  187.   Wimp_GetPointerInfo(&ptr);
  188.  
  189.   msg.header.size            = 80;
  190.   msg.header.yourref         = 0;
  191.   msg.header.action          = message_DATASAVE;
  192.   msg.data.datasave.window   = ptr.window;
  193.   msg.data.datasave.icon     = ptr.icon;
  194.   msg.data.datasave.pos      = ptr.pos;
  195.   msg.data.datasave.estsize  = saveblock->estimatedsize;
  196.   msg.data.datasave.filetype = saveblock->filetype;
  197.  
  198.   strcpy(msg.data.datasave.leafname,
  199.          LeafName(Icon_GetTextPtr(saveblock->window, saveblock->filenameicon)));
  200.  
  201.   Wimp_SendMessage(event_SENDWANTACK, &msg, ptr.window, ptr.icon);
  202.  
  203.   saveblock->last_message_ref = msg.header.myref;
  204.  
  205.   return TRUE;
  206. }
  207.  
  208.  
  209. static BOOL Shell_Save102__MenusDeletedOrWindowClosedHandler(event_pollblock *event,
  210.                                                     void *ref)
  211. {
  212.   Shell_Save102_saveblock *saveblock = (Shell_Save102_saveblock *)ref;
  213.  
  214.   /* Don't release handlers when menu/window is closed */
  215.   if(!saveblock->flags.data.release_after)
  216.     return FALSE;
  217.  
  218.   if((event->type == event_SEND && saveblock->flags.data.is_menu &&
  219.       event->data.message.header.action == message_MENUSDELETED) ||
  220.      (event->type == event_CLOSE  && saveblock->flags.data.is_save_window))
  221.   {
  222.     Shell_Save102_ReleaseSaveHandlers(ref);
  223.     free(saveblock);
  224.   }
  225.  
  226.   return FALSE;
  227. }
  228.  
  229.  
  230. static BOOL Shell_Save102__MessageHandler(event_pollblock *event, void *ref)
  231. {
  232.   Shell_Save102_saveblock *saveblock = (Shell_Save102_saveblock *)ref;
  233.   message_block  *msg = &event->data.message;
  234.  
  235.   if(event->type != event_ACK &&
  236.      msg->header.yourref != saveblock->last_message_ref)
  237.     return FALSE;
  238.   /* we are only interested in replies to our previous messages...
  239.      or unacknowledged messages */
  240.  
  241.   if(msg->header.action == message_DATASAVE)
  242.   {
  243.     /* User has dragged onto useless part of the desktop...
  244.      * This could be our original message_SENDWANTACK being sent to us
  245.      * because the sprite was dragged onto one of *our task's* windows,
  246.      * or a message_ACK sent to us by the WIMP because nobody responded
  247.      * to our original message.
  248.      */
  249.  
  250.     return FALSE;  /*  the app might want to deal with this
  251.                     *  message to save into itself.
  252.                     */
  253.   }
  254.  
  255.   if(msg->header.action == message_DATASAVEACK)
  256.   {
  257.     BOOL save_ok;
  258.  
  259.     save_ok = Shell_Save102__SaveDataToFilename(msg->data.datasaveack.filename,
  260.                                        saveblock);
  261.     if(save_ok)
  262.     {
  263.       message_block reply;
  264.  
  265.       memcpy(&reply, msg, sizeof(message_block));
  266.  
  267.       reply.header.action = message_DATALOAD;
  268.       reply.data.dataload.size = 49;
  269.       reply.header.yourref = reply.header.myref;
  270.  
  271.       Wimp_SendMessage(event_SENDWANTACK, &reply, reply.header.sender, 0);
  272.  
  273.       saveblock->last_message_ref = reply.header.myref;
  274.     }
  275.     else
  276.       Shell_Save102__ResetSaveBlock(saveblock);
  277.  
  278.     return TRUE;
  279.   }
  280.  
  281.   if(msg->header.action == message_RAMFETCH)
  282.   {
  283.     /* If we ignore message_RAMFETCH, the receiving task should
  284.      * try again using a transfer through <Wimp$Scrap>.
  285.      */
  286.     int           byteswritten;
  287.     BOOL          last_ramtransfer;
  288.     message_block reply;
  289.  
  290.     if(saveblock->ramsaver == NULL)
  291.       return TRUE;
  292.  
  293.     byteswritten = (saveblock->ramsaver)(event_taskhandle, saveblock->ref,
  294.                                          msg->header.sender,
  295.                                          msg->data.ramfetch.buffer,
  296.                                          msg->data.ramfetch.buffsize,
  297.                                          saveblock->ram_progress);
  298.  
  299.     last_ramtransfer = byteswritten < msg->data.ramfetch.buffsize;
  300.     saveblock->ram_progress += byteswritten;
  301.  
  302.     if(byteswritten < 0)
  303.     {
  304.       (saveblock->resulthandler)(Shell_Save102_RAMSAVERFAILED, saveblock);
  305.       Shell_Save102__ResetSaveBlock(saveblock);
  306.       return TRUE;
  307.     }
  308.  
  309.     memcpy(&reply, msg, sizeof(message_block));
  310.     reply.header.yourref = reply.header.myref;
  311.     reply.header.action  = message_RAMTRANSMIT;
  312.     reply.data.ramtransmit.byteswritten = byteswritten;
  313.  
  314.     Wimp_SendMessage((last_ramtransfer) ? event_SEND : event_SENDWANTACK,
  315.                      &reply, reply.header.sender, 0);
  316.  
  317.     saveblock->last_message_ref = reply.header.myref;
  318.  
  319.     if(last_ramtransfer)
  320.     {
  321.       Shell_Save102__ResetSaveBlock(saveblock);
  322.       if(saveblock->flags.data.quit_after_save)
  323.         Shell_Save102__CloseMenuOrSaveWindow(saveblock);
  324.  
  325.       (saveblock->resulthandler)(Shell_Save102_SAVEOK, saveblock->ref);
  326.     }
  327.  
  328.     return TRUE;
  329.   }
  330.  
  331.   if(msg->header.action == message_RAMTRANSMIT)
  332.   {
  333.     /* This is our message being returned to us by the Wimp  */
  334.     Shell_Save102__ResetSaveBlock(saveblock);
  335.     (saveblock->resulthandler)(Shell_Save102_RECEIVERFAILED, saveblock->ref);
  336.     return TRUE;
  337.   }
  338.  
  339.   if(msg->header.action == message_DATALOADACK)
  340.   {
  341.     /* everything OK  */
  342.     Shell_Save102__ResetSaveBlock(saveblock);
  343.     if(saveblock->flags.data.quit_after_save)
  344.       Shell_Save102__CloseMenuOrSaveWindow(saveblock);
  345.  
  346.     (saveblock->resulthandler)(Shell_Save102_SAVEOK, saveblock->ref);
  347.     return TRUE;
  348.   }
  349.  
  350.   if(msg->header.action == message_DATALOAD)
  351.   {
  352.     /* This is our message being returned to us by the Wimp  */
  353.     Error_Report(0, "Received DATALOAD back - scrap file not loaded...");
  354.     Shell_Save102__ResetSaveBlock(saveblock);
  355.  
  356.     (saveblock->resulthandler)(Shell_Save102_RECEIVERFAILED, saveblock->ref);
  357.     return TRUE;
  358.   }
  359.  
  360.   return FALSE;
  361. }
  362.  
  363.  
  364. static void Shell_Save102__DefaultResultHandler(Shell_Save102_result result, void *ref)
  365. {
  366.   UNUSED_ARG(ref);
  367.  
  368.   switch(result)
  369.   {
  370.     case Shell_Save102_RECEIVERFAILED:
  371.       Error_Report(0, "Receiver failed to load scrap file");
  372.       break;
  373.  
  374.     case Shell_Save102_FILESAVERFAILED:
  375.       Error_Report(0, "Filer-saver failed");
  376.       break;
  377.  
  378.     case Shell_Save102_RAMSAVERFAILED:
  379.       Error_Report(0, "RAM-saver failed");
  380.       break;
  381.   }
  382. }
  383.  
  384.  
  385. typedef BOOL (*Shell_Save102_eventclaimorreleasefn)(event_type    eventtype,
  386.                                            window_handle window,
  387.                                            icon_handle   icon,
  388.                                            event_handler handler,
  389.                                            void          *reference);
  390.   /* This just defines a function pointer which can point
  391.    * to the two functions Event_Claim and Event_Release.
  392.    */
  393.  
  394.  
  395. static void Shell_Save102__EventClaimOrRelease(Shell_Save102_saveblock *saveblock,
  396.                                       Shell_Save102_eventclaimorreleasefn fn)
  397. {
  398.   if(saveblock->dragsprite >= 0)
  399.   {
  400.     (fn)(event_CLICK, saveblock->window, saveblock->dragsprite,
  401.          Shell_Save102__DragIconClickHandler, saveblock);
  402.  
  403.     (fn)(event_USERDRAG, event_ANY, event_ANY,
  404.          Shell_Save102__UserDragHandler, saveblock);
  405.   }
  406.  
  407.   if(saveblock->okbutton >= 0)
  408.     (fn)(event_CLICK, saveblock->window, saveblock->okbutton,
  409.          Shell_Save102__OKIconHandler, saveblock);
  410.  
  411.   if(saveblock->cancelbutton >= 0)
  412.     (fn)(event_CLICK, saveblock->window, saveblock->cancelbutton,
  413.          Shell_Save102__CancelIconHandler, saveblock);
  414.  
  415.   (fn)(event_KEY, saveblock->window, saveblock->filenameicon,
  416.        Shell_Save102__KeyHandler, saveblock);
  417.  
  418.   (fn)(event_CLOSE, saveblock->window, event_ANY,
  419.        Shell_Save102__MenusDeletedOrWindowClosedHandler, saveblock);
  420.  
  421.   (fn)(event_SEND, event_ANY, event_ANY,
  422.        Shell_Save102__MenusDeletedOrWindowClosedHandler, saveblock);
  423.  
  424.   /* we always want to check whether to release the handlers
  425.    * when a menu has been closed because flags.data.is_menu
  426.    * may be changed after Save_InitSaveWindowHandler
  427.    */
  428.  
  429.   (fn)(event_SEND, event_ANY, event_ANY, Shell_Save102__MessageHandler, saveblock);
  430.   (fn)(event_SENDWANTACK, event_ANY, event_ANY,
  431.        Shell_Save102__MessageHandler, saveblock);
  432.   (fn)(event_ACK, event_ANY, event_ANY, Shell_Save102__MessageHandler, saveblock);
  433. }
  434.  
  435.  
  436.  
  437. Shell_Save102_saveblock *Shell_Save102_InitSaveWindowHandler(window_handle      window,
  438.                                            BOOL               is_menu,
  439.                                            BOOL               is_save_window,
  440.                                            BOOL               release_after,
  441.                                            icon_handle        dragsprite,
  442.                                            icon_handle        okbutton,
  443.                                            icon_handle        cancelbutton,
  444.                                            icon_handle        filenameicon,
  445.                                            Shell_Save102_filesaver     filesaver,
  446.                                            Shell_Save102_ramsaver      ramsaver,
  447.                                            Shell_Save102_resulthandler resulthandler,
  448.                                            size_t             estimatedsize,
  449.                                            int                filetype,
  450.                                            void               *ref)
  451. {
  452.   Shell_Save102_saveblock *saveblock;
  453.  
  454.   if(!filesaver)
  455.   {
  456.     /* Must have a file-saver  */
  457.     Error_Report(0, "Shell_Save102_InitSaveWindowHandler called with NULL filesaver");
  458.     return NULL;
  459.   }
  460.  
  461.   saveblock = malloc(sizeof(Shell_Save102_saveblock));
  462.   if(!saveblock)
  463.   {
  464.     Error_OutOfMemory(FALSE, "save window");
  465.     return NULL;
  466.   }
  467.  
  468.   saveblock->window                    = window;
  469.   saveblock->flags.data.is_menu        = is_menu;
  470.   saveblock->flags.data.is_save_window = is_save_window;
  471.   saveblock->flags.data.release_after  = release_after;
  472.   saveblock->dragsprite                = dragsprite;
  473.   saveblock->okbutton                  = okbutton;
  474.   saveblock->cancelbutton              = cancelbutton;
  475.   saveblock->filenameicon              = filenameicon;
  476.   saveblock->filesaver                 = filesaver;
  477.   saveblock->ramsaver                  = ramsaver;
  478.   saveblock->resulthandler             = resulthandler;
  479.   saveblock->estimatedsize             = estimatedsize;
  480.   saveblock->ref                       = ref;
  481.  
  482.   Shell_Save102_SetFiletype(saveblock, filetype);
  483.  
  484.   Shell_Save102__ResetSaveBlock(saveblock);
  485.  
  486.   if(saveblock->resulthandler == NULL)
  487.     saveblock->resulthandler = Shell_Save102__DefaultResultHandler;
  488.  
  489.   Shell_Save102__CleanIconText(saveblock->window, saveblock->filenameicon);
  490.   /*  Make sure the terminator of the filename is '\0' - templates
  491.    *  seem to come with a '\n' as terminator.
  492.    */
  493.  
  494.   Shell_Save102__EventClaimOrRelease(saveblock, Event_Claim);
  495.  
  496.   return saveblock;
  497. }
  498.  
  499.  
  500. void Shell_Save102_ReleaseSaveHandlers(Shell_Save102_saveblock *saveblock)
  501. {
  502.   Shell_Save102__EventClaimOrRelease(saveblock, Event_Release);
  503. }
  504.